package com.bJian.bJIanOJ.judge;

import cn.hutool.json.JSONUtil;
import com.bJian.bJIanOJ.common.ErrorCode;
import com.bJian.bJIanOJ.exception.BusinessException;
import com.bJian.bJIanOJ.judge.codeSandbox.CodeSandbox;
import com.bJian.bJIanOJ.judge.codeSandbox.codeSandboxFactory;
import com.bJian.bJIanOJ.judge.codeSandbox.codeSandboxProxy;
import com.bJian.bJIanOJ.judge.codeSandbox.model.ExecuteCodeRequest;
import com.bJian.bJIanOJ.judge.codeSandbox.model.ExecuteCodeResponse;
import com.bJian.bJIanOJ.judge.strategy.JudgeContext;
import com.bJian.bJIanOJ.mapper.question_submitMapper;
import com.bJian.bJIanOJ.model.dto.question.JudgeCase;
import com.bJian.bJIanOJ.model.dto.question.JudgeConfig;
import com.bJian.bJIanOJ.model.dto.question_submit.JudgeInfo;
import com.bJian.bJIanOJ.model.entity.Question;
import com.bJian.bJIanOJ.model.entity.question_submit;
import com.bJian.bJIanOJ.model.enums.JudgeInfoMessageEnum;
import com.bJian.bJIanOJ.model.enums.QuestionSubmitStatusEnum;
import com.bJian.bJIanOJ.service.QuestionService;
import com.bJian.bJIanOJ.service.question_submitService;
import lombok.extern.log4j.Log4j;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

import java.util.List;
import java.util.stream.Collectors;

@Component
@Slf4j
public class JudgeServiceImpl implements JudgeService,BeanPostProcessor {

    @Resource
    question_submitMapper questionSubmitMapper;

    @Resource
    QuestionService questionService;

    @Resource
    private JudgeManager judgeManager;


    @Value("${codesandbox.type:remote}")
    private String type;


//    @Override
//    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//        log.info("回调之前的信息：-->"+bean+",beanName:-->"+beanName);
//        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
//    }
//
//    @Override
//    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//        log.info("回调之后的信息：-->"+bean+",beanName:-->"+beanName);
//        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
//    }

    @Override
    public question_submit doJudge(long questionSubmitId) {
        //传入题目提交Id,获取对应的题目信息
        question_submit questionSubmitInfo = questionSubmitMapper.selectById(questionSubmitId);
        if (questionSubmitInfo == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        //获取题目信息
        Long questionId = questionSubmitInfo.getQuestionId();
        Question question = questionService.getById(questionId);
        if (question == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        //判断当前状态
        Integer status = questionSubmitInfo.getStatus();
        if (!status.equals(QuestionSubmitStatusEnum.WAITING.getValue())) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "已在判题或判题失败，请不要重复提交");
        }
        // 3）更改判题（题目提交）的状态为 “判题中”，防止重复执行
        questionSubmitInfo.setStatus(QuestionSubmitStatusEnum.RUNNING.getValue());
        int update = questionSubmitMapper.updateById(questionSubmitInfo);
        if (update<0) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "题目状态更新错误");
        }
        // 4）调用沙箱，获取到执行结果
        CodeSandbox codeSandbox = codeSandboxFactory.newInstanse(type);
        codeSandbox = new codeSandboxProxy(codeSandbox);
        String language = questionSubmitInfo.getLanguage();
        String code = questionSubmitInfo.getCode();
        //从JudgeCase中获取输入用例
        String judgeCaseStr = question.getJudgeCase();
        List<JudgeCase> judgeCaseList = JSONUtil.toList(judgeCaseStr, JudgeCase.class);
        List<String> inputList = judgeCaseList.stream().map(JudgeCase::getInput).collect(Collectors.toList());
        //创建运行沙箱需要的参数对象
        ExecuteCodeRequest executeCodeRequest = ExecuteCodeRequest.builder()
                .code(code)
                .language(language)
                .inputList(inputList)
                .build();
        //获取沙箱运行结果
        ExecuteCodeResponse executeCodeResponse = codeSandbox.executeCode(executeCodeRequest);

        //获取运行结果输出
        List<String> outputList = executeCodeResponse.getOutputList();
        JudgeInfo judgeInfo = new JudgeInfo();
        judgeInfo.setTime(executeCodeResponse.getJudgeInfo().getTime());
        judgeInfo.setMemory(executeCodeResponse.getJudgeInfo().getMemory());

        JudgeContext judgeContext = new JudgeContext();
        judgeContext.setJudgeInfo(judgeInfo);
        judgeContext.setOutputList(outputList);
        judgeContext.setJudgeCaseList(judgeCaseList);
        judgeContext.setQuestion(question);
        judgeContext.setQuestionSubmit(questionSubmitInfo);

        //调用判题管理器进行判题
        judgeInfo = judgeManager.doJudge(judgeContext);
        //把判题后的结果更新到数据库，以及修改题目判题状态
        questionSubmitInfo.setJudgeInfo(JSONUtil.toJsonStr(judgeInfo));
        questionSubmitInfo.setStatus(QuestionSubmitStatusEnum.SUCCEED.getValue());
        update = questionSubmitMapper.updateById(questionSubmitInfo);
        if (update<0) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "题目状态更新错误");
        }
        return questionSubmitInfo;
    }
}
